home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_200
/
264_01
/
ls.c
< prev
next >
Wrap
Text File
|
1980-01-01
|
16KB
|
661 lines
/*
* ls - list contents of directory
*
* Usage: ls [-alrstxzAR1] [path...]
*
* Flags:
* -a list all files, including hidden and system files, ".", and ".."
* -l long listing form (extra information)
* -r reverse order of sorting
* -s display size of each file in kilobytes, and total for each directory
* -t sort by time/date (latest first)
* -x sort by extension
* -z sort by size
* -A list all files except "." and ".."
* -R list subdirectories recursively
* -1 display 1 entry per line of short form
*
* This program is in the public domain.
* David MacKenzie
* 6522 Elgin Lane
* Bethesda, MD 20817
*
* Latest revision: 05/07/88
*/
#include <ctype.h>
#ifndef tolower
#define tolower(s) _tolower(s)
#endif
#include "getdir.h"
/* Arbitrary internal limit on filename path length. */
#define MAXPATH 125
/* For dynamically allocating space to store contents of each directory. */
#define ENTRIES_INCR 25
/*
* isdir(e)
* struct sablk *e;
*/
#define isdir(e) ((e)->sa_attrib & FA_DIREC)
/*
* kbytes(b)
* int b;
* Macro to return the number of kilobytes (rounded up) taken by a given
* number of bytes.
*/
#define kbytes(b) ((b) / 1024 + ((b) % 1024 != 0))
/* Shortened format for array in memory, to save space. */
struct sablk {
char sa_attrib;
unsigned sa_ftime;
unsigned sa_fdate;
unsigned long sa_fsize;
char *sa_fname;
};
/*
* Linked list of names of directories to list recursively (automatically
* initialized to NULL).
*/
struct dirs {
char *dirs_name;
struct dirs *dirs_next;
} *dirlist;
char dirbuf[512]; /* Buffer for disk input. */
char *monthtab[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
int aflag = 0; /* Display . and .. */
int lflag = 0; /* Long listing form. */
int rflag = 0; /* Reverse order of sort. */
int sflag = 0; /* Display file sizes. */
int tflag = 0; /* Sort by time/date. */
int xflag = 0; /* Sort by extension. */
int zflag = 0; /* Sort by size. */
int Aflag = 0; /* Display hidden and system files. */
int Rflag = 0; /* Display subdirectories recursively. */
int oneflag = 0; /* One entry per line in short listing. */
int listingargs; /* Boolean for sort comparison function. */
char *
Malloc(), *Realloc();
main(argc, argv)
int argc;
char **argv;
{
void listfiles(), listdir();
int entcmp();
struct sablk *initarray(), *saveent();
char *basename(), *index();
struct dirs *dirp;
struct ffblk *dir = (struct ffblk *) dirbuf;
struct sablk *save_array; /* Array of dir entries for sorting. */
int last_entry = -1; /* Last valid entry of save_array. */
int last_normal; /* Last non-directory entry. */
char pathbuf[MAXPATH]; /* Path of globbed arguments. */
char *tail; /* Tail component of pathbuf. */
int optind; /* Loop index. */
for (optind = 1; optind < argc && *argv[optind] == '-'; ++optind) {
while (*++argv[optind]) {
switch (*argv[optind]) {
case 'a':
aflag = Aflag = 1;
break;
case 'l':
lflag = 1;
break;
case 'r':
rflag = 1;
break;
case 's':
sflag = 1;
break;
case 't':
tflag = 1;
break;
case 'x':
xflag = 1;
break;
case 'z':
zflag = 1;
break;
case 'A':
Aflag = 1;
break;
case 'R':
Rflag = 1;
break;
case '1':
oneflag = 1;
break;
default:
printf("Usage: ls [-alrstxzAR1] [path...]\n");
exit(1);
break;
}
}
}
setdta(dirbuf); /* Set disk transfer area. */
if (optind == argc)
argv[argc++] = ".";
save_array = initarray();
for (; optind < argc; ++optind) {
/*
* Normally, when we say getfirst("dir") or getnext("dir"), where
* "dir" is the name of a directory, they return "dir" back to us
* along with its attributes, by which we discover that it has the
* FA_DIREC attribute. However, for certain pseudo-directories
* (which are real, regular directories on Unix), if we say, for
* instance, getfirst("\"), we get nothing back - no matches. To work
* around that problem, we have this special test for the problem
* pseudo-directories.
*/
if (isroot(argv[optind]) || isdot(argv[optind])) {
(void) strcpy(dir->ff_fname, argv[optind]);
dir->ff_attrib = FA_DIREC;
dir->ff_ftime = dir->ff_fdate = 0;
dir->ff_fsize = 0L;
save_array = saveent(save_array, dir, ++last_entry);
} else if (!getfirst(argv[optind], FA_ALL)) {
/*
* Copy any leading drive and/or path into pathbuf because the
* MS-DOS globbing routines return only the base of the
* filenames.
*/
(void) strcpy(pathbuf, argv[optind]);
tail = basename(pathbuf);
do {
if (dir->ff_fname[0] != '.' &&
(Aflag ||
(dir->ff_attrib & (FA_HIDDEN | FA_SYSTEM)) == 0)) {
(void) strcpy(tail, dir->ff_fname);
(void) strcpy(dir->ff_fname, pathbuf);
save_array = saveent(save_array, dir, ++last_entry);
}
} while (!getnext(argv[optind], FA_ALL));
} else if (index(argv[optind], '*') || index(argv[optind], '?')) {
printf("No match.\n");
exit(1);
}
}
listingargs = 1;
qsort((char *) save_array, last_entry + 1, sizeof(struct sablk),
entcmp);
/* Find last non-directory entry. */
for (last_normal = last_entry;
last_normal >= 0 && isdir(&save_array[last_normal]);
--last_normal);
/* First the regular listing... */
listfiles(save_array, last_normal);
/* ...then the directories. */
if (last_normal < last_entry) {
if (last_normal++ >= 0)
putchar('\n');
for (;;) {
listdir(save_array[last_normal].sa_fname, last_entry > 0);
/*
* We avoid a lot of memory waste by not using recursive function
* calls to implement recursive listing.
*/
while (dirlist) {
/* Chop head of list off and show it. */
dirp = dirlist;
dirlist = dirp->dirs_next;
putchar('\n');
/* This call might add a new head to the list! */
listdir(dirp->dirs_name, 1);
free(dirp->dirs_name);
free((char *) dirp);
}
if (++last_normal > last_entry)
break;
putchar('\n');
}
}
exit(0);
}
/*
* Display contents of one directory.
*/
void
listdir(name, label)
char *name; /* Name of directory to display. */
int label; /* Diplay the directory's name:? */
{
int entcmp();
void listfiles(), addsubdir();
char *concat(), *savestr();
struct sablk *save_array;
int last_entry;
int total_kbytes;
int i; /* Loop index. */
total_kbytes = getdir(name, &save_array, &last_entry);
if (label)
printf("%s:\n", name);
if (lflag || sflag)
printf("total %d\n", total_kbytes);
if (last_entry == -1)
return;
listingargs = 0;
qsort((char *) save_array, last_entry + 1, sizeof(struct sablk),
entcmp);
listfiles(save_array, last_entry);
if (Rflag)
for (i = last_entry; i >= 0; --i)
if (isdir(&save_array[i]) && save_array[i].sa_fname[0] != '.')
/* Add entry to list of subdirectories. */
addsubdir(concat(name, save_array[i].sa_fname));
for (i = 0; i <= last_entry; ++i)
free(save_array[i].sa_fname);
free(save_array);
}
/*
* Read contents of directory into array and return size in kilobytes.
*/
getdir(name, psave_array, plast_entry)
char *name;
struct sablk **psave_array;
int *plast_entry;
{
char *concat();
struct sablk *initarray(), *saveent();
struct ffblk *dir = (struct ffblk *) dirbuf;
struct sablk *save_array; /* Array of dir entries for sorting. */
int last_entry = -1; /* Last valid entry of save_array. */
int total_kbytes = 0; /* Ignored if sflag and lflag not given. */
char *nametmp;
int i; /* Temporary. */
save_array = initarray();
na